﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;

using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Design;

namespace JV.MVVM {

    [
        ToolboxItem( true ),
        ToolboxBitmap( typeof( Binder ), "binder.png" ),
        ProvideProperty( "Bindings", typeof( Control ) )
    ]
    public partial class Binder: Component, IExtenderProvider {

        #region ctors
        public Binder( ) {
            ControlBindingScripts = new Dictionary<Control, string>( );
            InitializeComponent( );

        }

        public Binder( IContainer container ) {
            container.Add( this );
            ControlBindingScripts = new Dictionary<Control, string>( );
            InitializeComponent( );
        }
        #endregion

        #region Control extension

        Dictionary<Control, string> ControlBindingScripts;

        public bool CanExtend( object extendee ) {
            return ( extendee is Control ) && !( extendee is Binder );
        }

        [
            Description("Binding settings"),
            Editor(typeof(BindingEditor), typeof(UITypeEditor))
        ]
        public string GetBindings( Control control ) {
            if ( !ControlBindingScripts.ContainsKey( control ) ) {
                return null;
            }
            return ControlBindingScripts[ control ];
        }

        public void SetBindings( Control control, string value ) {
            if ( string.IsNullOrWhiteSpace( value ) ) ControlBindingScripts.Remove( control );
            else {
                if ( ControlBindingScripts.ContainsKey( control ) ) ControlBindingScripts[ control ] = value;
                else ControlBindingScripts.Add( control, value );
            }
        }

        #endregion

        #region Binding

        INotifyPropertyChanged dc;
        List<BindHold> Binds = new List<BindHold>( );

        [
            Browsable( false ),
            EditorBrowsable( EditorBrowsableState.Never ),
            DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )
        ]
        public INotifyPropertyChanged DataContext {
            get { return dc; }
            set {
                if ( dc != value ) {
                    if ( dc != null ) UnBind( );
                    dc = value;
                    if ( dc != null ) Bind( );
                }
            }
        }

        void Bind( ) {

            var parser = new Parser( new Scanner( ) );
            foreach ( Control control in ControlBindingScripts.Keys ) {
                var tree = parser.Parse( ControlBindingScripts[ control ] );

                if ( tree.Errors.Count == 0 ) {
                    var bindingCol = tree.Nodes[ 0 ].Nodes[ 0 ];
                    for ( int i = 0; i < bindingCol.Nodes.Count; i++ ) {
                        var node = bindingCol.Nodes[ i ];
                        if ( node.Token.Type == TokenType.SEMICOLON ) continue;
                        Binds.Add( new BindHold( control, node, dc ) );
                    }
                }

            }

        }

        void UnBind( ) {
            for ( int i = 0; i < Binds.Count; i++ ) {
                Binds[ i ].Unbind( );
            }
        }

        #endregion

    }
}
